# Node.js 环境配置
# 这个文件包含所有 Node.js、npm、pnpm 相关的配置

# !! PATH安全处理重要说明 !!
# 1. PATH处理原则:
#    - Node.js相关路径不应覆盖系统路径
#    - ~/.n_env文件不应包含完整PATH，只存储必要的Node.js环境变量
#    - 在加载配置时，应保留系统路径的优先级
#
# 2. 历史问题:
#    - 之前将完整PATH存入~/.n_env，导致每次加载覆盖系统路径
#    - n_postinstall_hook()函数重复追加路径造成PATH膨胀
#    - 系统命令(ls、cat等)在Node.js版本切换后不可用
#
# 3. 当前解决方案:
#    - load_node_env()安全加载.n_env，跳过PATH设置
#    - 确保系统路径优先，Node.js路径次之
#    - n_postinstall_hook()不再将PATH写入.n_env
#    - 使用deduplicate_path()函数去除重复路径

# 导入日志工具
if [ -f "$HOME/.mac_sync/log_utils.zsh" ]; then
  source "$HOME/.mac_sync/log_utils.zsh"
fi

# 基本日志函数（如果 log_utils.zsh 不可用）
if ! type log_info > /dev/null 2>&1; then
  log_info() { echo "ℹ️ $1"; }
  log_success() { echo "✅ $1"; }
  log_warning() { echo "⚠️ $1"; }
  log_error() { echo "❌ $1"; }
  log_header() { echo -e "\n=== $1 ===\n"; }
  log_node() { echo "⬢ Node.js: $1"; }
  log_npm() { echo "📦 NPM: $1"; }
  log_pnpm() { echo "🔄 PNPM: $1"; }
  log_path() { echo "📁 $1: $2"; }
  log_env() { echo "🌍 $1: $2"; }
  log_version() { echo "$1: $2"; }
fi

# 首先定义 n 命令包装器，确保优先级最高
function n() {
  echo "💡 n 函数被调用：n $@"
  
  # 保存当前版本以便之后比较
  local old_version=$(node -v 2>/dev/null || echo "none")
  echo "📊 当前版本: $old_version"
  
  # 执行原始的 n 命令
  if [ -x "$N_PREFIX/bin/n" ]; then
    # 直接调用 n 命令，不设置 SHELL 环境变量
    "$N_PREFIX/bin/n" "$@"
  elif command -v /usr/local/bin/n >/dev/null 2>&1; then
    /usr/local/bin/n "$@"
  else
    echo "❌ 找不到 n 命令"
    return 1
  fi
  
  # 获取命令的返回值
  local result=$?
  
  # 如果命令执行成功
  if [ $result -eq 0 ]; then
    # 获取新版本
    local new_version=$(node -v 2>/dev/null || echo "none")
    echo "📊 新版本: $new_version"
    
    # 如果版本发生变化，执行钩子函数
    if [ "$old_version" != "$new_version" ] && [ "$new_version" != "none" ]; then
      echo "✅ 版本已从 $old_version 切换到 $new_version，正在更新环境配置..."
      # 给系统一点时间完成版本切换
      sleep 1
      n_postinstall_hook
    fi
  fi
  
  return $result
}

# Node.js version manager (n)
export N_PREFIX="$HOME/.n"
export PATH="$N_PREFIX/bin:$PATH"

# 定义统一的全局包根目录
NODE_GLOBAL_ROOT="$HOME/.node_global"

# 根据Node.js版本获取对应的分组目录
function get_node_group() {
  local major_version=$1
  
  if [ "$major_version" -le 14 ]; then
    echo "legacy"  # 14及以下版本
  elif [ "$major_version" -le 19 ]; then
    echo "middle"  # 15-19版本
  else
    echo "modern"  # 20及以上版本
  fi
}

# 初始化全局目录
function setup_global_dirs() {
  local group=$1
  
  # 创建npm目录
  local npm_dir="${NODE_GLOBAL_ROOT}/${group}/npm"
  mkdir -p "${npm_dir}/bin"
  chmod 755 "${npm_dir}"
  
  # 创建pnpm目录
  local pnpm_dir="${NODE_GLOBAL_ROOT}/${group}/pnpm"
  mkdir -p "${pnpm_dir}/bin"
  mkdir -p "${pnpm_dir}/store"
  chmod 755 "${pnpm_dir}"
  
  echo "${npm_dir}:${pnpm_dir}"
}

# npm configuration
# 这些变量将在 postinstall 钩子中动态设置
export NPM_CONFIG_PREFIX="$HOME/.npm-global"
export PNPM_HOME="$HOME/.pnpm-global"
export PATH="$NPM_CONFIG_PREFIX/bin:$PNPM_HOME/bin:$PATH"

# ensure npm uses the correct node
export npm_config_node_gyp="$N_PREFIX/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js"

# 加载最新的环境变量
function load_node_env() {
  if [ -f "$HOME/.n_env" ]; then
    # 保存当前PATH
    local original_path="$PATH"
    
    # 安全检查：确保系统路径包含基本命令目录
    local essential_paths="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
    if ! echo "$PATH" | grep -q "/usr/bin" || ! echo "$PATH" | grep -q "/bin"; then
      PATH="$essential_paths:$PATH"
    fi
    
    # 将系统路径放在前面
    local system_paths=""
    for essential_path in $(echo $essential_paths | tr ':' ' '); do
      if [[ ! ":$PATH:" == *":$essential_path:"* ]]; then
        system_paths="$system_paths:$essential_path"
      fi
    done
    
    # 移除开头的冒号
    system_paths=${system_paths#:}
    
    # 安全加载配置，但跳过PATH设置
    while IFS= read -r line; do
      # 跳过注释行和PATH设置行
      if [[ ! "$line" =~ ^# ]] && [[ ! "$line" =~ PATH ]]; then
        eval "$line"
      fi
    done < "$HOME/.n_env"
    
    # 构建新的PATH，确保Node.js路径在系统路径后面
    if [ -n "$NPM_CONFIG_PREFIX" ] && [ -n "$PNPM_HOME" ]; then
      # 使用之前保存的原始PATH，而不是.n_env中的PATH
      export PATH="$essential_paths:$N_PREFIX/bin:$NPM_CONFIG_PREFIX/bin:$PNPM_HOME/bin"
    else
      export PATH="$essential_paths:$N_PREFIX/bin"
    fi
    
    # 确保PATH中包含所有自定义路径（排除Node.js相关路径）
    for path_item in $(echo $original_path | tr ':' ' '); do
      if [[ "$path_item" != *"node"* ]] && [[ "$path_item" != *"npm"* ]] && [[ "$path_item" != *"pnpm"* ]]; then
        if [[ ! ":$PATH:" == *":$path_item:"* ]]; then
          export PATH="$PATH:$path_item"
        fi
      fi
    done
    
    # 去除PATH中的重复路径
    if type deduplicate_path > /dev/null 2>&1; then
      export PATH=$(deduplicate_path "$PATH")
    fi
    
    log_success "已加载 Node.js $(node -v 2>/dev/null || echo '未安装') 的环境变量"
  fi
}

# 自动加载当前 Node.js 版本对应的环境变量
load_node_env

# Global packages management
function backup_global_packages() {
  local version=$(node -v)
  local backup_file="$HOME/.npm_global_packages_${version}.txt"
  log_info "备份当前 Node.js ${version} 的全局包列表..."
  npm list -g --depth=0 > "$backup_file"
  log_success "备份完成：$backup_file"
}

function restore_global_packages() {
  local version=$(node -v)
  local backup_file="$HOME/.npm_global_packages_${version}.txt"
  if [ -f "$backup_file" ]; then
    log_info "发现 Node.js ${version} 的全局包备份，开始恢复..."
    cat "$backup_file" | grep -v "npm list" | grep "@" | awk -F" " '{print $2}' | while read package; do
      if ! npm list -g "$package" &>/dev/null; then
        log_info "安装包：$package"
        npm install -g "$package"
      else
        log_info "包已存在，跳过：$package"
      fi
    done
    log_success "全局包恢复完成"
  else
    log_warning "没有找到 Node.js ${version} 的全局包备份"
  fi
}

# n postinstall hook
n_postinstall_hook() {
  local version=$(node -v 2>/dev/null || echo "none")
  if [ "$version" = "none" ]; then
    log_warning "Node.js 未安装，开始安装..."
    return 0
  fi
  
  local major_version=$(echo $version | cut -d 'v' -f2 | cut -d '.' -f1)
  log_node "版本切换到: $version (主版本: $major_version)"
  
  # 获取版本分组
  local group=$(get_node_group $major_version)
  log_info "使用 $group 环境分组"
  
  # 设置和创建目录
  local dirs=$(setup_global_dirs $group)
  local npm_dir=$(echo $dirs | cut -d ':' -f1)
  local pnpm_dir=$(echo $dirs | cut -d ':' -f2)
  
  # 保存原始PATH中的系统路径部分
  # 首先保存一份完整的系统路径，确保包含所有重要系统目录
  local essential_paths="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
  
  # 保存原始PATH中的系统路径部分和重要用户路径
  local system_paths=""
  local IFS=":"
  for path_item in $PATH; do
    # 保留所有系统路径（不包含 home 目录的路径）以及特定的用户目录
    if [[ "$path_item" != "$HOME"* ]] || [[ "$path_item" == *"/Library/"* ]] || [[ "$path_item" == *"/Applications/"* ]]; then
      if [ -z "$system_paths" ]; then
        system_paths="$path_item"
      else
        system_paths="$system_paths:$path_item"
      fi
    fi
  done
  
  # 确保系统路径中包含基本系统目录
  for essential_path in $(echo $essential_paths | tr ':' ' '); do
    if [[ ! ":$system_paths:" == *":$essential_path:"* ]]; then
      system_paths="$system_paths:$essential_path"
    fi
  done
  
  # 清除旧的 NPM_CONFIG_PREFIX 和 PNPM_HOME
  unset NPM_CONFIG_PREFIX
  unset PNPM_HOME
  
  # 设置新的环境变量
  export NPM_CONFIG_PREFIX="$npm_dir"
  export PNPM_HOME="$pnpm_dir"
  
  # 清理 .npmrc 中可能存在的硬编码 prefix
  if [ -f "$HOME/.npmrc" ]; then
    grep -v "^prefix=" "$HOME/.npmrc" > "$HOME/.npmrc.tmp"
    mv "$HOME/.npmrc.tmp" "$HOME/.npmrc"
  fi
  
  # 确保 Node.js 二进制文件在 PATH 中
  local node_bin_path="$N_PREFIX/bin"
  
  # 构建新的 PATH，确保包含所有必要的系统路径
  export PATH="$node_bin_path:$NPM_CONFIG_PREFIX/bin:$PNPM_HOME/bin:$system_paths"
  # 去除PATH中的重复路径
  export PATH=$(deduplicate_path "$PATH")
  log_info "PATH 环境变量已更新和去重"
  
  # 现在 Node.js 和 npm 在 PATH 中，可以安全地使用它们
  npm config set prefix "$NPM_CONFIG_PREFIX"
  
  # 根据 Node.js 版本安装兼容的包管理器
  if [ "$major_version" -lt 14 ]; then
    # Node.js 12-13 使用兼容的 npm 版本
    log_info "为 Node.js $major_version 安装兼容的 npm 版本..."
    npm install -g npm@6
    
    log_warning "注意：此版本的 Node.js 不支持 pnpm，只使用 npm"
    
  elif [ "$major_version" -le 16 ]; then
    # Node.js 14-16 使用兼容的 npm 和 pnpm 版本
    log_info "为 Node.js $major_version 安装兼容的 npm 版本..."
    npm install -g npm@6
    
    log_info "为 Node.js $major_version 安装兼容的 pnpm 版本..."
    npm install -g pnpm@6
    
    # 配置 pnpm
    pnpm config set global-dir "$PNPM_HOME"
    pnpm config set global-bin-dir "$PNPM_HOME/bin"
    # 设置 pnpm 存储路径
    pnpm config set store "$PNPM_HOME/store"
    
  elif [ "$major_version" -lt 20 ]; then
    # Node.js 17-19 使用兼容的 npm 版本
    log_info "为 Node.js $major_version 安装兼容的 npm 版本..."
    npm install -g npm@10.2.4
    
    log_info "为 Node.js $major_version 安装兼容的 pnpm 版本..."
    npm install -g pnpm@8.15.4
    
    # 配置 pnpm
    pnpm config set global-dir "$PNPM_HOME"
    pnpm config set global-bin-dir "$PNPM_HOME/bin"
    # 设置 pnpm 存储路径
    pnpm config set store-dir "$PNPM_HOME/store"
    
  else
    # Node.js 20+ 使用最新版本
    log_info "为 Node.js $major_version 安装最新的 npm 版本..."
    npm install -g npm@latest
    
    log_info "为 Node.js $major_version 安装最新的 pnpm 版本..."
    npm install -g pnpm@latest
    
    # 配置 pnpm
    pnpm config set global-dir "$PNPM_HOME"
    pnpm config set global-bin-dir "$PNPM_HOME/bin"
    # 设置 pnpm 存储路径
    pnpm config set store-dir "$PNPM_HOME/store"
  fi
  
  # 显示环境信息
  log_header "当前环境信息"
  log_node "$(node -v 2>/dev/null || echo '未安装')"
  log_npm "$(npm -v 2>/dev/null || echo '未安装') (全局目录: $NPM_CONFIG_PREFIX)"
  if [ "$major_version" -ge 14 ]; then
    log_pnpm "$(pnpm -v 2>/dev/null || echo '未安装') (全局目录: $PNPM_HOME)"
  fi
  log_env "PATH" "$PATH"
  
  # 添加当前配置到 ~/.n_env 文件，方便其他脚本读取
  echo "# Node.js 环境配置 - 由 n_postinstall_hook 创建于 $(date)" > "$HOME/.n_env"
  echo "#" >> "$HOME/.n_env"
  echo "# !! 警告 !! 此文件只应包含Node.js环境变量，不应包含PATH设置" >> "$HOME/.n_env"
  echo "# 包含PATH会导致系统命令不可用，因为系统路径可能被覆盖" >> "$HOME/.n_env"
  echo "# 如需修改PATH，请在单独的脚本中进行，并确保系统路径优先" >> "$HOME/.n_env"
  echo "#" >> "$HOME/.n_env"
  echo "export NODE_GLOBAL_ROOT=\"$NODE_GLOBAL_ROOT\"" >> "$HOME/.n_env"
  echo "export NPM_CONFIG_PREFIX=\"$NPM_CONFIG_PREFIX\"" >> "$HOME/.n_env"
  echo "export PNPM_HOME=\"$PNPM_HOME\"" >> "$HOME/.n_env"
  echo "# PATH变量由mac_env.zsh和各环境模块动态构建，不在此存储" >> "$HOME/.n_env"
  
  # 显示配置信息
  log_success "Node.js $major_version 环境配置已更新 (使用 $group 分组目录)"
  log_info "PATH 环境变量已更新 (注意：PATH不再保存到.n_env文件中，而是动态构建)"
}

# 添加 n 的 postinstall 钩子
export N_POST_INSTALL_HOOK="n_postinstall_hook"

# Environment check function
function check_node_env() {
  log_header "Node.js 环境信息"
  log_node "$(node -v 2>/dev/null || echo '未安装')"
  log_npm "$(npm -v 2>/dev/null || echo '未安装')"
  log_pnpm "$(pnpm -v 2>/dev/null || echo '未安装')"
  log_version "N 版本管理器" "$(n --version 2>/dev/null || echo '未安装')"
  log_header "全局安装目录"
  log_path "NPM" "$NPM_CONFIG_PREFIX"
  log_path "PNPM" "$PNPM_HOME"
}

# Environment management functions
function backup_node_modules() {
  local backup_dir="$HOME/.node_modules_backup/$(date +%Y%m%d_%H%M%S)"
  log_info "备份 node_modules 到 $backup_dir"
  mkdir -p "$backup_dir"
  if [ -d "node_modules" ]; then
    cp -R node_modules "$backup_dir"
    log_success "备份完成"
  else
    log_warning "当前目录没有 node_modules"
  fi
}

# 显示全局包目录信息
function node_global_info() {
  log_header "Node.js 全局包目录信息"
  
  # 检查全局目录根目录
  if [ -d "$NODE_GLOBAL_ROOT" ]; then
    log_path "全局包根目录" "$NODE_GLOBAL_ROOT"
    
    # 获取当前版本分组
    local version=$(node -v 2>/dev/null || echo "none")
    if [ "$version" != "none" ]; then
      local major_version=$(echo $version | cut -d 'v' -f2 | cut -d '.' -f1)
      local group=$(get_node_group $major_version)
      log_info "当前版本: $version (分组: $group)"
      
      # 显示当前分组目录
      log_path "当前 npm 目录" "$NPM_CONFIG_PREFIX"
      log_path "当前 pnpm 目录" "$PNPM_HOME"
    fi
    
    # 统计各个分组的空间占用
    if command -v du >/dev/null 2>&1; then
      log_header "各分组存储空间"
      
      for group_dir in "$NODE_GLOBAL_ROOT"/*; do
        if [ -d "$group_dir" ]; then
          local group_name=$(basename "$group_dir")
          local size=$(du -sh "$group_dir" | awk '{print $1}')
          log_info "$group_name: $size"
        fi
      done
    fi
  else
    log_warning "全局包根目录尚未创建"
  fi
}

# 清理指定分组的全局包
function clean_node_global() {
  local group="$1"
  
  if [ -z "$group" ]; then
    log_error "请指定要清理的分组 (legacy/middle/modern)"
    return 1
  fi
  
  local target_dir="$NODE_GLOBAL_ROOT/$group"
  
  if [ -d "$target_dir" ]; then
    log_warning "将清理 $group 分组的全局包目录: $target_dir"
    log_warning "此操作不可撤销，请确认 (输入 y 继续)"
    read -r confirm
    
    if [ "$confirm" = "y" ]; then
      log_info "开始清理 $group 分组..."
      rm -rf "$target_dir"
      mkdir -p "$target_dir/npm/bin" "$target_dir/pnpm/bin" "$target_dir/pnpm/store"
      chmod -R 755 "$target_dir"
      log_success "$group 分组已清理并重新创建目录结构"
    else
      log_info "已取消清理操作"
    fi
  else
    log_error "找不到分组目录: $target_dir"
    return 1
  fi
}

function export_global_packages() {
  local export_file="$HOME/.npm_global_packages.txt"
  npm list -g --depth=0 > "$export_file"
  log_success "全局包列表已导出到 $export_file"
}

function import_global_packages() {
  local import_file="$HOME/.npm_global_packages.txt"
  if [ -f "$import_file" ]; then
    log_info "正在安装全局包..."
    cat "$import_file" | grep -v "npm list" | grep "@" | awk -F" " '{print $2}' | xargs npm install -g
    log_success "安装完成"
  else
    log_error "找不到包列表文件"
  fi
}

# 初始检查当前 Nodejs 版本
log_header "当前 Nodejs 环境"
log_node "$(/usr/bin/head -n 1 < <(node -v 2>&1) || echo '未安装')"

# 初始检查当前 pnpm 版本
log_pnpm "$(/usr/bin/head -n 1 < <(pnpm -v 2>&1) || echo '未安装')"

# 初始检查当前 npm 版本
log_npm "$(/usr/bin/head -n 1 < <(npm -v 2>&1) || echo '未安装')"

# npm/yarn/pnpm aliases
alias ni="npm install"
alias nd="npm run dev"
alias ns="npm run serve"
alias nb="npm run build"
alias nis="npm install && npm run serve"
alias nid="npm install && npm run dev"
alias p="pnpm"

# Development environment aliases
alias check-env="check_node_env"
alias node-env="check_node_env"
alias backup-modules="backup_node_modules"
alias save-packages="export_global_packages"
alias restore-packages="import_global_packages"
alias node-global="node_global_info"
alias clean-node-global="clean_node_global"

# 路径信息命令
alias node-paths="log_node_paths" 